package touro.mancala.slave;

import static touro.mancala.core.Constants.PLAYER_BOTTOM;
import static touro.mancala.core.Constants.PLAYER_TOP;

import java.util.LinkedList;
import java.util.StringTokenizer;

public class Board {
	Store[] pitsAndStores;
	int[] players;
	int numMoves;
	int activePlayer;
	int score;

	public Board () {
		this(4);
		numMoves = 0;
	}

	public Board (int numStones) {
		this.players = new int[2];
		players[0] = PLAYER_BOTTOM;
		players[1] = PLAYER_TOP;
		activePlayer = players[0];
		pitsAndStores = new Store[14];
		
		for (int i = 0; i < 7; i++){
			if (i == 6) {
				pitsAndStores[i] = new Store(players[0]);
			} else {
				pitsAndStores[i] = new Pit(numStones, players[0], i);
			}
		}

		for (int i = 7; i < 14; i++){
			if (i == 13) {
				pitsAndStores[i] = new Store(players[1]);
			} else {
				pitsAndStores[i] = new Pit(numStones, players[1], i);
			}
		}
		numMoves = 0;
		score = 0;
	}

	public Board (int[] numbers){
		this.players = new int[2];
		players[0] = 0;
		players[1] = 1;
		activePlayer=players[0];
		pitsAndStores = new Store[14];
		for (int i = 0; i < 7; i++){
			if (i == 6) {
				pitsAndStores[i] = new Store(numbers[i], players[0]);
			} else {
				pitsAndStores[i] = new Pit(numbers[i], players[0], i);
			}
		}
	
		for (int i = 7; i < 14; i++){
			if (i == 13) {
				pitsAndStores[i] = new Store(numbers[i], players[1]);
			} else {
				pitsAndStores[i] = new Pit(numbers[i], players[1], i);
			}
		}
		numMoves = 0;
		score = 0;
	}

	public Board (Board board) {
		pitsAndStores = new Store[14];
		players = new int[2];
		players[0] = 0;
		players[1] = 1;
		activePlayer=players[0];
		pitsAndStores = new Store[14];
		for (int i = 0; i < 7; i++){
			if (i == 6) {
				pitsAndStores[i] = new Store(board.pitsAndStores[i]);
			} else {
				pitsAndStores[i] = new Pit((Pit)board.pitsAndStores[i]);
			}
		}

		for (int i = 7; i < 14; i++){
			if (i == 13) {
				pitsAndStores[i] = new Store(board.pitsAndStores[i]);
			} else {
				pitsAndStores[i] = new Pit((Pit)board.pitsAndStores[i]);
			}
		}

		numMoves = board.numMoves;
		score = board.score;
	}
	
	public Board(String stringBoard, String active, boolean hasStores) {
		this(getNumStones(stringBoard, hasStores));
		
		activePlayer = Integer.parseInt(active);
		
	}

	public static int[] getNumStones(String stringBoard, boolean hasStores) {
		StringTokenizer split = new StringTokenizer(stringBoard, ".");
		int[] numStones = new int[14];
		for (int i = 0; i < 14; i++) {
			if((i==6 || i==13) && !hasStores) {
				numStones[i] = 0;
			} else if ((i==6 || i==13) && hasStores){
				numStones[i] = Integer.parseInt(split.nextToken());
			} else {
				numStones[i] = Integer.parseInt(split.nextToken());
			}
		}
		
		
		return numStones;
	}

	
	
	
	public int getActivePlayer() {
		return activePlayer;
	}

	public void setActivePlayer(int activePlayer) {
		this.activePlayer = activePlayer;
	}

	public Store getStore (int index) {
		return pitsAndStores[index];
	}

	public Store getMyStore (int p) {
		return (p == (pitsAndStores[6].getPlayer())) ? pitsAndStores[6] : pitsAndStores[13];
	}

	public Store[] getPitsAndStores() {
		return pitsAndStores;
	}
	
	public boolean isPitEmpty( int pitNumber ) {
		return pitsAndStores[pitNumber].getSize() == 0;
	}

	public boolean isEmpty (int p) {
		int ind = p == (pitsAndStores[6].getPlayer()) ? 0 : 7;
		for (int i = ind; i < 6+ind; i++) {
			if (pitsAndStores[i].getSize() > 0) {
				return false;
			}
		}
		return true;
	}



	public int getNumMoves() {
		return numMoves;
	}

	public void setNumMoves(int numMoves) {
		this.numMoves = numMoves;
	}
	
	
	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public void nextPlayer() {
		int active = oppositePlayer(activePlayer);
		activePlayer = players[active];
	}
	
	public int oppositePlayer(int player) {
		return player == PLAYER_BOTTOM ? PLAYER_TOP : PLAYER_BOTTOM;
	}
	
	//returns the difference between the stones in the 
	//param player's pit and the stones in the other player's pit
	public int diffStores(int player) {
		int myStones = getMyStore(player).getSize();
		int otherStones = getMyStore(oppositePlayer(player)).getSize();
		return myStones-otherStones;
	}

	public boolean sow(int index) {
		return this.sow((Pit)pitsAndStores[index]);
	}

	public boolean sow(Pit myPit) {
		int stones = myPit.removeStones();

		int place = myPit.getPlace();
		
		boolean goAgain = false;

		for (int i = 0; i<stones; i++) {
			place++;
			place = place%14;
			boolean placed = false;
			while (!placed) {
				if (pitsAndStores[place] instanceof Pit || pitsAndStores[place].getPlayer() == (myPit.getPlayer())) {
					pitsAndStores[place].addStone();
					placed = true;
				} else {
					place++;
					place = place%14;
				}
			}
		}
		//place is now the place of the last stone sown. It must have been sown either in the
		//player's store or in any of the pits so the if statements check where it was sown
		boolean isPlayerMyPlayer = pitsAndStores[place].getPlayer()==(myPit.getPlayer());

		if (!(pitsAndStores[place] instanceof Pit) && isPlayerMyPlayer) {
			goAgain = true;
		} else if (isPlayerMyPlayer && pitsAndStores[place].getSize() == 1 && pitsAndStores[12-place].getSize() > 0){
			Store myStore = this.getMyStore(pitsAndStores[place].getPlayer());
			int myStones = ((Pit)pitsAndStores[place]).removeStones();
			int otherStones = ((Pit)pitsAndStores[12-place]).removeStones();
			myStore.addStones(myStones);
			myStore.addStones(otherStones);
		}
		
		score = diffStores(activePlayer);
		score += (goAgain ? 2 : 0);
		
		if(!goAgain) {
			nextPlayer();
		}

		numMoves++;
		
		return goAgain;
	}


	//This method will return a linked list with all of the children boards of this board
	public LinkedList<Board> getChildrenBoards(){
		LinkedList<Board> childrenBoards=new LinkedList<Board>();

		int index = activePlayer * 7;
		for(int i=index; i<index+6; i++){
			if(!pitsAndStores[i].isEmpty()) {
				Board child = new Board(this);
				child.sow(i);	
				childrenBoards.add(child);
			}
		}
		return childrenBoards;
	}
	
	

	public String toString(){
		String temp="";
		for (int i=0; i<14; i++){
			temp+=pitsAndStores[i].getSize()+".";
		}
		return temp;
	}
}



